/**
 /**
 * The graphical class for the Eight Queens game.
 * 
 * @author Dzulhafizi Abidin
 */

package mainClasses;


import pieces.*;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.Point;

import java.awt.event.ActionListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import org.w3c.dom.*;
import java.io.File;
import org.w3c.dom.*;

import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException; 
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.DocumentBuilder;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException; 
import javax.lang.model.element.Element;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.soap.Node;

import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import java.awt.event.ActionEvent;

@SuppressWarnings("unused")

public class GraphicalEightQueens extends JPanel implements BoardGame{

	/**
	 * The size of the board (same value for width and length)
	 */
	private static final int SIZE = 8;
	
	
	/**
	 * A constant used to remember the number of queens that must be used in this game
	 */
	private static final int NUMBER_OF_QUEENS = 8;
	
	
	/**
	 * Declaration of the board used in this game
	 */
	private Board board1;	
	
	
	/**
	 * An array of Queens that contains all the eight queens used in this game
	 */
	private Queen[] queens;
	
	
	/**
	 * An integer used to keep track of the number of queens that have been placed on the board
	 */
	private int count = 0;
	
	
	/**
	 * A boolean value used to determine whether a specified square is currently occupied by a queen or not
	 */
	Boolean[][] hasQueen;
	
	boolean[][] QueenPath;
	/**
	 * A fixed value of dimension used for the window in this game
	 */
	Dimension d = new Dimension(800, 700);
	
	
	/**
	 * A 2D-array of buttons to represent the squares on the board
	 */
	JButton[][] buttons;
	
	
	/**
	 * Instance of InputAndOutput that is used to input and output error and feedback messages to the player
	 */
	InputAndOutput io;


	/**
	 * Buttons that are placed on the InputAndOutput Label
	 */
	JButton restart = new JButton("Restart");
	JButton exit = new JButton("Exit");
	JButton promptButtons[];
	
	
	/**
	 * For the purpose of undo and redo
	 */
	public int moveNumber = 0;
	ArrayList<Board> boardsundo = new ArrayList<Board>();
	ArrayList<Queen[]> queensundo = new ArrayList<Queen[]>();
	ArrayList<Boolean[][]> hasQueenundo = new ArrayList<Boolean[][]>();
	ArrayList<boolean[][]> QueenPathundo = new ArrayList<boolean[][]>();
	ArrayList<Integer> countundo = new ArrayList<Integer>();
	
	public int moveNumberRedo = 0;
	ArrayList<Board> boardsredo = new ArrayList<Board>();
	ArrayList<Queen[]> queensredo = new ArrayList<Queen[]>();
	ArrayList<Boolean[][]> hasQueenredo = new ArrayList<Boolean[][]>();
	ArrayList<boolean[][]> QueenPathredo = new ArrayList<boolean[][]>();
	ArrayList<Integer> countredo = new ArrayList<Integer>();
	
	
	
	/**
	 * The constructor for GraphicalEightQueens class. It receives an instance
	 * of InputAndOutput that is used to communicate with the player for 
	 * error messages and selections
	 */
	public GraphicalEightQueens(InputAndOutput io){
		this.setSize(d);
		this.setLayout(new GridLayout(SIZE, SIZE));
		this.board1 = new Board();
		this.io = io;
		

		this.promptButtons = new JButton[2];
		this.promptButtons[0] = this.restart;
		this.promptButtons[1] = this.exit;
		this.restart.addActionListener(this);
		this.exit.addActionListener(this);
		
	
		buttons = new JButton[SIZE][SIZE];
		hasQueen = new Boolean[SIZE][SIZE];
		queens = new Queen[8];
		
		for (int i = SIZE-1; i >= 0; i--) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				JButton temp = new JButton();
				temp.addActionListener(this);
				buttons[i][j]=temp;
				this.add(temp);		
				hasQueen[i][j] = false;
			}
		}
		
		QueenPath = new boolean[SIZE][SIZE];
		for (int i = SIZE-1; i >= 0; i--) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				this.QueenPath[i][j] = false;
			}
		}
		for(int j = 0; j<SIZE; j++)
		{
			this.queens[j]=new Queen(SIZE, SIZE, this.board1, "Black");
		}
		
		this.io.setMode(InputAndOutput.LABEL);
		this.io.addButtons(promptButtons);
		this.print();
		this.io.setOutputField("You have 8 queens to place.");
		this.io.setOutputField("Go on and place your first Queen.");
		this.io.setVisible(true);
		this.setVisible(true);
	}
	
	
	
	
	
	
	/**
     * Responds to button presses on the chess board and acts accordingly
     * 
     * @param e - An event that is created when a button is pressed
     */
	public void actionPerformed(ActionEvent e) {
		
		if(e.getSource()==restart)
		{
			this.restart();
		}
		
		if(e.getSource()==exit)
		{
			System.exit(0);
		}
		
		else{
			for (int i = SIZE-1; i >= 0; i--) 
			{
				for (int j = 0; j < SIZE; j++) 
				{
					if(e.getSource() == buttons[i][j])
					{
						if (count < NUMBER_OF_QUEENS)
						{
							this.saveCurrentState();
							Queen queen = new Queen(i,j,this.board1,"White");
							this.queens[count] = queen;
							count++;
							this.moveNumber++;
							if (this.queenThreat())
							{
								count--;
								this.queens[count] = new Queen(SIZE, SIZE, this.board1, "Black");
								deleteCurrentState();
								this.print();
								this.io.setOutputField("There are threats from other queens. Please select other squares!");
								this.io.setVisible(true);
								continue;
							}
							
							if (hasQueen[i][j]){
								count--;
								this.io.setOutputField("There's already a Queen placed over there. Please select other squares!");
								deleteCurrentState();
								this.io.setVisible(true);
								continue;
							}
							this.moveNumberRedo = 0;
							this.boardsredo = new ArrayList<Board>();
							this.queensredo = new ArrayList<Queen[]>();
							this.hasQueenredo = new ArrayList<Boolean[][]>();
							this.QueenPathredo = new ArrayList<boolean[][]>();
							this.countredo = new ArrayList<Integer>();
							this.board1.add(queen);
							this.hasQueen[i][j] = true;
							this.markQueenPath(queen);
							
							this.print();
							
							if (count <8){
								this.io.setOutputField("You have placed " + count + " queens. You can't put your next queen on red-colored squares!");
								if(findLost())
								{
									this.io.setOutputField("You have no more place on the board for your " + (8-count) + " other queens, You lost");
									this.io.setMode(InputAndOutput.LABEL_AND_BUTTONS);
								}
								this.io.setVisible(true);
							}
							else{
								this.io.setOutputField("YOU HAVE WON!! Press RESTART for a new game or EXIT to quit.");
								this.io.setMode(InputAndOutput.LABEL_AND_BUTTONS);
								this.io.setVisible(true);
							}
								
							continue;
						}
						
						
					}
				}
			}
		}
	}

	
	
	/**
    * Loads the current state of the board from a chessxml file
    * It sets the appropriate instance variables to allow the user to continue
    * the game using the saved settings
    */
	public void load()
	{
		String fileName = "temp";
		File file = new File(fileName);
		JFileChooser chooseFile = new JFileChooser();
		chooseFile.showOpenDialog(chooseFile);
		file = chooseFile.getSelectedFile();
		
		if(file!=null){
			fileName = file.getAbsolutePath();
			if(!fileName.endsWith(".chessxml"))
			{
				this.io.setOutputField("You have selected an invalid file");
				return;
			}
	    	
		}
		else{fileName = null;}
		
		if(fileName!=null)
		{
			this.restart();
			
			 try {
		            DocumentBuilderFactory documentBuilder = DocumentBuilderFactory.newInstance();
		            DocumentBuilder docBuild = documentBuilder.newDocumentBuilder();
		            Document doc = docBuild.parse (new File(fileName));
		            doc.getDocumentElement ().normalize ();
		            NodeList ListOfQueen = doc.getElementsByTagName("queen");
		            int totalQueens = ListOfQueen.getLength();
		            for(int s=0; s<ListOfQueen.getLength() ; s++){
		                org.w3c.dom.Node firstQueenNode = ListOfQueen.item(s);
		                if(firstQueenNode.getNodeType() == Node.ELEMENT_NODE){
		                	org.w3c.dom.Element firstQueenElement = (org.w3c.dom.Element)firstQueenNode;
		                	org.w3c.dom.NodeList firstQueenList = firstQueenElement.getElementsByTagName("side");
		                    org.w3c.dom.Element sideElement = (org.w3c.dom.Element)firstQueenList.item(0);
	
		                    org.w3c.dom.NodeList sideNodes = sideElement.getChildNodes();
		                    org.w3c.dom.NodeList xList = firstQueenElement.getElementsByTagName("x");
		                    org.w3c.dom.Element xElement = (org.w3c.dom.Element)xList.item(0);
	
		                    org.w3c.dom.NodeList xNode = xElement.getChildNodes();
		                    org.w3c.dom.NodeList yList = firstQueenElement.getElementsByTagName("y");
		                    org.w3c.dom.Element yElement = (org.w3c.dom.Element)yList.item(0);
	
		                    org.w3c.dom.NodeList yNode = yElement.getChildNodes();
		                    
		                    String xString = ((org.w3c.dom.Node)xNode.item(0)).getNodeValue().trim();
		                    int x = (int)xString.charAt(0)-48;
		                    String yString = ((org.w3c.dom.Node)yNode.item(0)).getNodeValue().trim();
		                    int y = (int)yString.charAt(0)-48;
		                    String sideString = ((org.w3c.dom.Node)sideNodes.item(0)).getNodeValue().trim();
		                    this.saveCurrentState();
		                    Queen loadedQueen = new Queen(x, y, this.board1, sideString); 
		                    this.queens[count] = loadedQueen;
		                    if(loadedQueen.getSide().equals("White"))
		                    {
								count++;
								this.moveNumber++;
								this.moveNumberRedo = 0;
								this.boardsredo = new ArrayList<Board>();
								this.queensredo = new ArrayList<Queen[]>();
								this.hasQueenredo = new ArrayList<Boolean[][]>();
								this.QueenPathredo = new ArrayList<boolean[][]>();
								this.countredo = new ArrayList<Integer>();
								this.board1.add(loadedQueen);
								this.hasQueen[x][y] = true;
								this.markQueenPath(loadedQueen);
		                    }
		                    if (count <8){
								this.io.setOutputField("You have placed " + count + " queens. You can't put your next queen on red-colored squares!");
								if(findLost())
								{
									this.io.setOutputField("You have no more place on the board for your " + (8-count) + " other queens, You lost");
									this.io.setMode(InputAndOutput.LABEL_AND_BUTTONS);
								}
								this.io.setVisible(true);
							}
							else{
								this.io.setOutputField("YOU HAVE WON!! Press RESTART for a new game or EXIT to quit.");
								this.io.setMode(InputAndOutput.LABEL_AND_BUTTONS);
								this.io.setVisible(true);
							}
							
							this.print();
		                }
		            }
		        }catch (SAXParseException err) {
		        System.out.println ("** Parsing error" + ", line " + err.getLineNumber () + ", uri " + err.getSystemId ());
		        System.out.println(" " + err.getMessage ());
	
		        }catch(FileNotFoundException fnfe)
		        {
		        	JOptionPane.showMessageDialog(this, "Cannot find a saved game in this file: ", "File not found warning", JOptionPane.INFORMATION_MESSAGE, null);
		        }catch (SAXException e) {
		        Exception x = e.getException ();
		        ((x == null) ? e : x).printStackTrace ();
	
		        }catch (Throwable t) {
		        t.printStackTrace ();
		        }
			}
		
	    }//end of main
	
	
	
	
	/**
     * Saves the current state of the game into a chessxml file
     * @throws IOException
     */
	public void save() throws IOException 
	{
		String s = "";
		s += "<eightQueen>";
		for(int i=0; i<8; i++)
		{
			Queen queenSave = this.queens[i];
			s += "<queen>";
			if(queenSave.getSide().equals("White"))
			{
				s += "<side>";
				s += "White";
				s += "</side>";
			}else
			{
				s += "<side>";
				s += "Black";
				s += "</side>";
			}
			s += "<x>";
			s += "" + queenSave.getX();
			s += "</x>";
			s += "<y>";
			s += "" + queenSave.getY();
			s += "</y>";
			s += "</queen>";
		}
		s+= "</eightQueen>";
		this.writeToFile(s);
	}
	
	
	
	/**
     * Writes the current state of the board into an chessxml file for save and load functions
     * @param s The string that represents the current state of the board (in xml)
     * @throws IOException
     */
	public void writeToFile(String s) throws IOException 
	{
		String fileName = "temp";
		File file = new File(fileName);
		JFileChooser chooseFile = new JFileChooser();
		chooseFile.showSaveDialog(chooseFile);
		file = chooseFile.getSelectedFile();
		
		if(file!=null){
			fileName = file.getAbsolutePath()+ ".chessxml";
		}
		else{fileName = null;}
		
		if(fileName!=null)
		{
			FileOutputStream out = new FileOutputStream(fileName);
		 try {
				 byte[] b = s.getBytes();
				 out.write(b, 0, s.length());
		      } finally {
		    	  out.close();
		      }
	     }
	}
	
	
	
	/**
	 * Saves the current state of the board to be used in the undo and redo functions
	 */
	public void saveCurrentState()
	{
		if(moveNumber<0)
		{
			moveNumber = 0;
		}
		Integer countvalue = new Integer(this.count);
		this.countundo.add(this.moveNumber, countvalue);
		Board b = this.board1.createBoard();
		this.boardsundo.add(this.moveNumber, b);
		Queen[] q = new Queen[this.SIZE];
		for(int x = 0; x<SIZE; x++)
		{
			Queen temp = this.queens[x];
			Queen qu = new Queen(temp.getX(), temp.getY(), b, temp.getSide());
			q[x] = qu;
		}
		this.queensundo.add(this.moveNumber, q);
		
		Boolean[][] hq = new Boolean[this.SIZE][this.SIZE];
		for(int i = 0; i<this.SIZE; i++)
		{
			for(int j=0; j<this.SIZE; j++)
			{
				Boolean temp = false;
				hq[i][j] = temp;
			}
		}
		this.hasQueenundo.add(this.moveNumber, hq);
		
		boolean[][] qpu = new boolean[this.SIZE][this.SIZE];
		for(int i = 0; i<this.SIZE; i++)
		{
			for(int j=0; j<this.SIZE; j++)
			{
				boolean temp = false;
				qpu[i][j] = temp;
			}
		}
		this.QueenPathundo.add(this.moveNumber, qpu);
		
		JButton[][] bu = new JButton[this.SIZE][this.SIZE];
		for(int i = 0; i<this.SIZE; i++)
		{
			for(int j=0; j<this.SIZE; j++)
			{
				JButton temp = new JButton();
				temp.addActionListener(this);
				bu[i][j] = temp;
				if(!this.buttons[i][j].isEnabled())
				{
					bu[i][j].setBackground(this.buttons[i][j].getBackground());
					bu[i][j].setEnabled(false);
				}
			}
		}
		this.print();
	}
	
	
	
	/**
	 * Removes the current state from the undo and redo list
	 */
	public void deleteCurrentState()
	{
		this.moveNumber--; //Decrements the move number
		if(moveNumber<0)
		{
			moveNumber = 0;
		}
		this.boardsundo.remove(this.moveNumber);
		this.queensundo.remove(this.moveNumber);
		this.hasQueenundo.remove(this.moveNumber);
		this.QueenPathundo.remove(this.moveNumber);
		this.countundo.remove(this.moveNumber);
	}
	
	
	
	
	/**
	 * Prints the current state of the board onto the array of buttons
	 */
	public void print()
	{
		for (int i = SIZE-1; i >= 0; i--) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				if((i+j)%2 == 0)
				{
					buttons[i][j].setBackground(new Color(70, 5, 3));
					if(!this.buttons[i][j].isEnabled())
					{
						buttons[i][j].setBackground(new Color(255, 0, 0));
					}
				}else
				{
					buttons[i][j].setBackground(Color.white);
					if(this.QueenPath[i][j])
					{
						buttons[i][j].setBackground(new Color(255, 0, 0));
					}
				}
				
				if(this.board1.getPiece(i, j) instanceof NullPiece)
				{
					buttons[i][j].setIcon(new ImageIcon("WHITENULL.GIF"));
				}else if(this.board1.getPiece(i, j) instanceof Queen && this.board1.getPiece(i, j).getSide().equals("White"))
				{
					buttons[i][j].setIcon(new ImageIcon("Wh-QUEEN-W.PNG"));
				}else if(this.board1.getPiece(i, j) instanceof Queen && this.board1.getPiece(i, j).getSide().equals("Black"))
				{
					buttons[i][j].setIcon(new ImageIcon("Ba-QUEEN-W.PNG"));
				}
			}
		}
		this.setVisible(true);
	}
	
	
	/**
	 * Determines whether the player has placed all eight queens on the board or not
	 * 
	 * @return A Boolean value set to true if the player had won the game and false otherwise
	 */
	private boolean hasWon(){
		
		if(count == NUMBER_OF_QUEENS)
		{
			return true;
		}
		return false;
	}
	


	
	
	/**
	 * Check the queens in the array of queens, whether they threaten each other or not
	 * 
	 * @return A Boolean value set to true if at least one queen is threatening another queen in the array and false otherwise
	 */
	public boolean queenThreat()
	{
		for (int i=0; i<NUMBER_OF_QUEENS; i++)
		{
			Queen temp = this.queens[i];
			for(int j=0; j<NUMBER_OF_QUEENS; j++)
			{
				if(temp.isEqual(this.queens[j])!=true && this.queens[j].getSide()=="White" && temp.getSide()=="White")
				{
					if(temp.eightQueenMove(this.queens[j].getX(), this.queens[j].getY()))
					{
						return true;
					}
				}
			}
		}
		return false;
	}
	
	
	
	/**
	 * This method will mark the possible path on the board for the given parameter Queen q
	 */
	public void markQueenPath(Queen q)
	{
		for (int i = 0; i < SIZE; i++) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				if(q.movePossible(i, j))
				{
					QueenPath[i][j] = true;
					buttons[i][j].setEnabled(false);
				}
			}
		}
	}
	
	
	
	/**
	 * Restarts the game, with a whole new board and empty array of queens. The 2D array of buttons will also be refreshed.
	 */
	public void restart()
	{
		this.moveNumber = 0;
		this.boardsundo = new ArrayList<Board>();
		this.queensundo = new ArrayList<Queen[]>();
		this.hasQueenundo = new ArrayList<Boolean[][]>();
		this.QueenPathundo = new ArrayList<boolean[][]>();
		this.countundo = new ArrayList<Integer>();
		
		this.moveNumberRedo = 0;
		this.boardsredo = new ArrayList<Board>();
		this.queensredo = new ArrayList<Queen[]>();
		this.hasQueenredo = new ArrayList<Boolean[][]>();
		this.QueenPathredo = new ArrayList<boolean[][]>();
		this.countredo = new ArrayList<Integer>();
		
		this.board1 = new Board();
		this.count = 0;
		
		
		for(int j = 0; j<SIZE; j++)
		{
			this.queens[j]=new Queen(SIZE, SIZE, this.board1, "Black");
		}
		
		JButton buttontemp = new JButton();
		for (int i = SIZE-1; i >= 0; i--) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				hasQueen[i][j] = false;
				buttons[i][j].setBackground(buttontemp.getBackground());
				buttons[i][j].setEnabled(true);
				this.QueenPath[i][j]=false;
			}
		}
		this.io.setOutputField("A new game has started!");
		this.io.setOutputField("Your Have 8 Queen to place on the board.");
		this.io.setMode(InputAndOutput.LABEL);
		this.io.setVisible(true);
		
		this.print();
	}

	
	
	/**
	 * Return true if all the blocks on the board either have a queen or are threatened
	 * by another queen
	 * @return A boolean set to true if the game is lost
	 */
	public boolean findLost()
	{
		int counter = 0;
		for (int i = SIZE-1; i >= 0; i--) 
		{
			for (int j = 0; j < SIZE; j++) 
			{
				if(!this.buttons[i][j].isEnabled())
				{
					counter++;
				}
			}
		}
		if(this.count!=8)
		{
			if((this.count + counter)==64)
			{
				return true;
			}
		}
		return false;
	}

	
	
	/**
	 * Repeats a step that was made and was previously undo'ed.
	 */
	public void redo() {
		if(this.moveNumberRedo>0)
		{
			if(moveNumber<0)
			{
				this.moveNumber = 0;
				
			}
			this.moveNumberRedo--;
			this.board1 = this.boardsredo.get(moveNumberRedo);
			this.queens = this.queensredo.get(moveNumberRedo);
			this.hasQueen = this.hasQueenredo.get(moveNumberRedo);
			this.QueenPath = this.QueenPathredo.get(moveNumberRedo);
			this.count = this.countredo.get(moveNumberRedo).intValue();
			
			JButton tempbutton = new JButton();
			for(int x=0; x<this.SIZE; x++)
			{
				for(int y=0; y<this.SIZE; y++)
				{
					this.buttons[x][y].setEnabled(true);
					this.buttons[x][y].setBackground(tempbutton.getBackground());
				}
			}
			for(int i=0; i<this.SIZE; i++)
			{
				if(!this.queens[i].getSide().equals("Black"))
				{
					Queen currentqueen = this.queens[i];
					this.markQueenPath(currentqueen);
				}
			}
			
			this.moveNumber++;
			
			if(this.boardsundo.size()==0)
			{
				this.moveNumber = 0;
			}
			this.boardsundo.add(this.moveNumber, this.boardsredo.get(moveNumberRedo));
			this.queensundo.add(this.moveNumber, this.queensredo.get(moveNumberRedo));
			this.hasQueenundo.add(this.moveNumber, this.hasQueenredo.get(moveNumberRedo));
			this.QueenPathundo.add(this.moveNumber, this.QueenPathredo.get(moveNumberRedo));
			this.countundo.add(this.moveNumber, this.countredo.get(moveNumberRedo));
			
			this.boardsredo.remove(moveNumberRedo);
			this.queensredo.remove(moveNumberRedo);
			this.hasQueenredo.remove(moveNumberRedo);
			this.QueenPathredo.remove(moveNumberRedo);
			this.countredo.remove(moveNumberRedo);
			
			if(moveNumberRedo==0)
			{
				this.boardsredo = new ArrayList<Board>();
				this.queensredo = new ArrayList<Queen[]>();
				this.hasQueenredo = new ArrayList<Boolean[][]>();
				this.QueenPathredo = new ArrayList<boolean[][]>();
				this.countredo = new ArrayList<Integer>();
			}
			this.print();
		}else
		{
			this.io.setOutputField("No more redo move possible.");
		}
		if(this.boardsundo.size()==0)
		{
			this.moveNumber = 0;
		}
		
	}



	/**
	 * Returns the game to the previous state. It undo's the last step and
	 * saves it as a redo step
	 */
	public void undo() {
		if(this.moveNumber>0)
		{			
			this.saveCurrentState();
			if(this.boardsredo.size()==0)
			{
				this.moveNumberRedo = 0;
			}
			this.boardsredo.add(moveNumberRedo, this.boardsundo.get(moveNumber));
			this.queensredo.add(moveNumberRedo, this.queensundo.get(moveNumber));
			this.hasQueenredo.add(moveNumberRedo, this.hasQueenundo.get(moveNumber));
			this.QueenPathredo.add(moveNumberRedo, this.QueenPathundo.get(moveNumber));
			this.countredo.add(moveNumberRedo, this.countundo.get(moveNumber));
			
			this.moveNumberRedo++;
			this.boardsundo.remove(moveNumber);
			this.queensundo.remove(moveNumber);
			this.hasQueenundo.remove(moveNumber);
			this.QueenPathundo.remove(moveNumber);
			this.countundo.remove(moveNumber);
			this.moveNumber--;
			
			this.board1 = this.boardsundo.get(moveNumber);
			this.queens = this.queensundo.get(moveNumber);
			this.hasQueen = this.hasQueenundo.get(moveNumber);
			this.QueenPath = this.QueenPathundo.get(moveNumber);
			this.count = this.countundo.get(moveNumber).intValue();
			
			this.io.setMode(this.io.LABEL);
			this.io.setOutputField("You have selected to undo.");
			this.io.setOutputField("Select you next Queen's location.");
			JButton tempbutton = new JButton();
			for(int x=0; x<this.SIZE; x++)
			{
				for(int y=0; y<this.SIZE; y++)
				{
					this.buttons[x][y].setEnabled(true);
					this.buttons[x][y].setBackground(tempbutton.getBackground());
				}
			}
			for(int i=0; i<this.SIZE; i++)
			{
				if(!this.queens[i].getSide().equals("Black"))
				{
					Queen currentqueen = this.queens[i];
					this.markQueenPath(currentqueen);
				}
			}
			this.print();
			if(moveNumber==0)
			{
				this.boardsundo = new ArrayList<Board>();
				this.queensundo = new ArrayList<Queen[]>();
				this.hasQueenundo = new ArrayList<Boolean[][]>();
				this.QueenPathundo = new ArrayList<boolean[][]>();
				this.countundo = new ArrayList<Integer>();

				this.saveCurrentState();
				moveNumber = 0;
			}
		}else
		{
			this.moveNumber = -1;
			this.io.setOutputField("No more undo move possible.");
			this.io.setOutputField("Select you next Queen's location.");
		}
		if(this.boardsredo.size()==0)
		{
			this.moveNumberRedo = 0;
		}
		
	}
	

}
